﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Geometric
{
    class NOCVector2D
    {
        public double x;
        public double y;
        public double originalLen;

        public NOCVector2D()
        {
            this.x = 0;
            this.y = 0;
            this.originalLen = 0.0;
        }

        public NOCVector2D(double x, double y)
        {
            this.x = x;
            this.y = y;
            this.originalLen = 0.0;
        }

        public NOCVector2D reverse()
        {
            double n_x = -this.x;
            double n_y = -this.y;
            return new NOCVector2D(n_x, n_y);
        }

        public void subVector(ref NOCVector2D vector)
        {
            this.x -= vector.x;
            this.y -= vector.y;
        }

        public NOCVector2D subedVector(ref NOCVector2D vector)
        {
            double n_x = this.x - vector.x;
            double n_y = this.y - vector.y;
            return new NOCVector2D(n_x, n_y);
        }

        public void addConstant(double value)
        {
            this.x += value;
            this.y += value;
        }

        public NOCVector2D addedConstant(double value)
        {
            double n_x = this.x + value;
            double n_y = this.y + value;

            return new NOCVector2D(n_x, n_y);
        }

        public void mulConstant(double value)
        {
            this.x *= value;
            this.y *= value;
        }

        public NOCVector2D muledConstant(double value)
        {
            double n_x = this.x * value;
            double n_y = this.y * value;
            return new NOCVector2D(n_x, n_y);
        }

        public void addVector(ref NOCVector2D vector)
        {
            this.x += vector.x;
            this.y += vector.y;
        }


        public NOCVector2D addedVector(ref NOCVector2D vector)
        {
            double n_x = this.x + vector.x;
            double n_y = this.y + vector.y;
            return new NOCVector2D(n_x, n_y);
        }

        
        public NOCVector2D rotated(double angle)
        {
            // 逆时针旋转：
            //| cos_a, -sin_a |
            //| sin_a,  cos_a |
            //要想顺时针 使用-a代替a即可
            double cos_a = Math.Cos(angle);
            double sin_a = Math.Sin(angle);

            double n_x = this.x * cos_a - this.y * sin_a;
            double n_y = this.x * sin_a + this.y * cos_a;

            return new NOCVector2D(n_x, n_y);
        }

        public void rotate(double angle)
        {
            double cos_a = Math.Cos(angle);
            double sin_a = Math.Sin(angle);
            double n_x = this.x * cos_a - this.y * sin_a;
            double n_y = this.x * sin_a + this.y * cos_a;
            this.x = n_x;
            this.y = n_y;
        }

        public double dotProducts(ref NOCVector2D vector)
        {
            double v = this.x * vector.x + this.y * vector.y;
            return v;
        }
        public double vectorLength()
        {
            return Math.Sqrt(Math.Pow(this.x, 2) + Math.Pow(this.y, 2));
        }
        public NOCVector2D normalized()
        {
            double len = this.vectorLength();
            if (len == 0.0)
            {
                return new NOCVector2D(this.x, this.y);
            }
            double n_x = this.x / len;
            double n_y = this.y / len;
            return new NOCVector2D(n_x, n_y);
        }
        public void normalize()
        {
            double len = this.vectorLength();
            if (len != 0.0)
            {
                this.originalLen = len;
                this.x /= len;
                this.y /= len;
            }
        }
        public double crossProducts(ref NOCVector2D vector)
        {
            // 若this转到vector的方向为逆时针，那么返回正值
            // 若this转到vector的方向为顺时针，那么返回负值
            double v = this.x * vector.y - vector.x * this.y;
            return v;
        }

        public double angleToVector(ref NOCVector2D vector, bool toAngle = true, bool shortestArc = true)
        {
            // 返回从当前向量到目标向量的夹角
            // 默认为 按照最短的圆弧走， 就是 上半圆为逆时针角 都是大于0的
            // 下半园为顺时针角，都是小于0的
            // shortestArc 设置为false时，全部时逆时针 角 0~360之间
            double cos_zeta = this.dotProducts(ref vector)/(this.vectorLength() * vector.vectorLength());
            double zeta = Math.Acos(cos_zeta);
            double cross = this.crossProducts(ref vector);
            

            if( shortestArc )
            {
                int sign = cross >= 0 ? 1 : -1;
                zeta *= sign;
            }
            else
            {
                if(cross < 0)
                {
                    zeta = NOCConstant.Pi*2 - zeta;
                }
            }


            zeta = (180 * zeta) / NOCConstant.Pi;
            return zeta;
        }

        public double projectionOfVector(ref NOCVector2D vector)
        {
            // 计算向量vector 投影到本向量的长度
            // 有符号，表示方向
            double dot_value = this.dotProducts(ref vector);
            double projectLen = dot_value / this.vectorLength();
            return projectLen;
        }
    }
}
